/**
 * 日志管理模块
 *
 * @fileoverview 提供应用程序的统一日志管理功能，基于Winston构建。
 * 支持多级日志输出、文件轮转、性能监控、错误跟踪等高级功能。
 *
 * 核心功能：
 * - 结构化日志记录（JSON格式）
 * - 日志文件自动轮转（按日期和大小）
 * - 追踪ID和关联ID生成
 * - 上下文感知的日志记录
 * - 性能监控和指标统计
 * - 错误聚合和分析
 * - HTML报告生成
 *
 * @author System
 * @version 1.0.0
 * @since 2024
 *
 * @example
 * ```typescript
 * import { getLogger, createContextLogger } from './logger'
 *
 * // 获取默认日志器
 * const logger = getLogger()
 * logger.info('应用启动', { version: '1.0.0' })
 *
 * // 创建上下文日志器
 * const contextLogger = createContextLogger({ component: 'UserService' })
 * contextLogger.debug('用户登录', { userId: 123 })
 * ```
 */

import type { LogContext as ILogContext } from './types'
import { mkdir, writeFile } from 'node:fs/promises'
import { join } from 'node:path'
import { performance } from 'node:perf_hooks'
import process from 'node:process'
import dayjs from 'dayjs'
import winston from 'winston'
import DailyRotateFile from 'winston-daily-rotate-file'
import { getConfig, getLogsPath, getTempHtmlPath } from '../config/index'
import { sanitize } from './sanitize'
import { LogCategory } from './types'
import 'dayjs/locale/zh-cn'

// 配置 dayjs 中文
dayjs.locale('zh-cn')

/** Winston 日志器实例 */
let logger: winston.Logger | null = null
/** 运行期已应用的日志配置快照（用于热更新对比） */
let appliedLogLevel: string | null = null
let appliedConsoleOutput: boolean | null = null
let appliedFileOutput: boolean | null = null

/**
 * 按需应用运行期日志配置（热更新）。
 *
 * - 无需重启即可变更 log_level、console_output、file_output
 * - 通过设置 transport.level 与 transport.silent 达到动态控制
 */
function applyRuntimeLoggingConfigIfNeeded(): void {
  if (!logger)
    return
  try {
    const cfg = getConfig()
    const desiredLevel = String(cfg?.logging?.log_level || 'INFO').toLowerCase()
    const desiredConsole = !!cfg?.logging?.console_output
    const desiredFile = !!cfg?.logging?.file_output

    // 若无变化，直接返回
    if (appliedLogLevel === desiredLevel && appliedConsoleOutput === desiredConsole && appliedFileOutput === desiredFile)
      return

    // 更新主日志器级别
    if (logger.level !== desiredLevel)
      logger.level = desiredLevel

    // 更新各 transport 的级别与静默开关
    for (const t of logger.transports) {
      try {
        // 控制台输出
        if (t instanceof winston.transports.Console) {
          ;(t as any).level = desiredLevel
          ;(t as any).silent = !desiredConsole
          continue
        }
        // 文件轮转输出
        if (t instanceof DailyRotateFile) {
          const fn: string = (t as any).filename || ''
          // error-%DATE%.log 固定 error 级别
          if (/error-%DATE%\.log$/i.test(fn) || /error-\d{4}-\d{2}-\d{2}\.log$/i.test(fn)) {
            ;(t as any).level = 'error'
            ;(t as any).silent = !desiredFile
          }
          else {
            ;(t as any).level = desiredLevel
            ;(t as any).silent = !desiredFile
          }
          continue
        }
        // 其他 transport：尽量对齐主级别
        ;(t as any).level = desiredLevel
      }
      catch {}
    }

    appliedLogLevel = desiredLevel
    appliedConsoleOutput = desiredConsole
    appliedFileOutput = desiredFile
  }
  catch {
    // 配置尚未加载或异常时忽略
  }
}

// ============================================================================
// 追踪ID管理函数
// ============================================================================

/**
 * 生成追踪ID
 *
 * @description 为每个操作生成唯一的追踪标识符，用于跟踪请求链路
 * @returns {string} 追踪ID，格式：timestamp-random-counter
 *
 * @example
 * ```typescript
 * const traceId = generateTraceId()
 * // 返回类似：1mz5k8x-abc123-001
 * ```
 */
export function generateTraceId(): string {
  return TraceIdGenerator.generate()
}

/**
 * 生成关联ID
 *
 * @description 用于关联相关的操作和事件，在分布式系统中特别有用
 * @returns {string} 关联ID，格式：corr-timestamp-random
 */
export function generateCorrelationId(): string {
  return TraceIdGenerator.generateCorrelationId()
}

// ============================================================================
// 类型定义和接口
// ============================================================================

// LogContext 类型已移至 types.ts，此处使用导入的类型
type LogContext = ILogContext

/**
 * 追踪ID生成器
 *
 * @description 负责生成唯一的追踪标识符和关联标识符
 * @class TraceIdGenerator
 */
class TraceIdGenerator {
  /** 内部计数器，确保ID唯一性 */
  private static counter = 0

  /**
   * 生成追踪ID
   *
   * @returns {string} 格式化的追踪ID
   */
  static generate(): string {
    const timestamp = dayjs().valueOf().toString(36)
    const random = Math.random().toString(36).substr(2, 6)
    const counter = (++this.counter).toString(36).padStart(3, '0')
    return `${timestamp}-${random}-${counter}`
  }

  /**
   * 生成关联ID
   *
   * @returns {string} 格式化的关联ID
   */
  static generateCorrelationId(): string {
    return `corr-${dayjs().valueOf()}-${Math.random().toString(36).substr(2, 8)}`
  }
}

/**
 * 日志统计指标管理器
 *
 * @description 收集和管理日志系统的运行指标，用于性能监控和分析
 * @class LogMetrics
 */
class LogMetrics {
  /** 指标计数器映射 */
  private static counters = new Map<string, number>()
  /** 上次重置时间戳 */
  private static lastReset = dayjs().valueOf()

  /**
   * 递增指定指标的计数
   *
   * @param {string} metric - 指标名称
   */
  static increment(metric: string): void {
    this.counters.set(metric, (this.counters.get(metric) || 0) + 1)
    this.checkReset()
  }

  /**
   * 获取所有指标数据
   *
   * @returns {Record<string, number>} 指标名称到数值的映射
   */
  static getMetrics(): Record<string, number> {
    return Object.fromEntries(this.counters)
  }

  /**
   * 重置所有指标
   */
  static resetMetrics(): void {
    this.counters.clear()
    this.lastReset = dayjs().valueOf()
  }

  private static checkReset(): void {
    try {
      const config = getConfig()
      if (config.logging.metrics.enabled) {
        const resetInterval = config.logging.metrics.reset_interval_hours * 60 * 60 * 1000
        if (dayjs().valueOf() - this.lastReset > resetInterval) {
          this.resetMetrics()
        }
      }
    }
    catch {
      // 配置未加载时跳过
    }
  }

  static getStats(): { totalLogs: number, uptime: number, metricsAge: number } {
    const totalLogs = Array.from(this.counters.values()).reduce((sum, count) => sum + count, 0)
    return {
      totalLogs,
      uptime: Math.round(process.uptime()),
      metricsAge: Math.round((dayjs().valueOf() - this.lastReset) / 1000),
    }
  }
}

// 日志采样器
class LogSampler {
  // 按分类的采样率配置
  private static categorySamplingRates: Record<LogCategory, number> = {
    [LogCategory.BOOKING]: 1.0, // 预约业务日志 100%（全记录）
    [LogCategory.MONITOR]: 1.0, // 监控任务日志 100%（全记录）
    [LogCategory.BATCH]: 1.0, // 批量操作日志 100%（全记录）
    [LogCategory.HTTP]: 0.1, // HTTP请求日志 10%（采样）
    [LogCategory.DATABASE]: 1.0, // 数据库操作日志 100%（全记录）
    [LogCategory.IPC]: 0.5, // IPC通信日志 50%（采样）
    [LogCategory.WORKER]: 0.5, // Worker进程日志 50%（采样）
    [LogCategory.SYSTEM]: 1.0, // 系统日志 100%（全记录）
    [LogCategory.PERFORMANCE]: 0.2, // 性能监控日志 20%（采样）
    [LogCategory.SECURITY]: 1.0, // 安全相关日志 100%（全记录）
    [LogCategory.BROWSER]: 0.2, // 浏览器操作日志 20%（采样）
    [LogCategory.PROXY]: 0.3, // 代理相关日志 30%（采样）
  }

  private static shouldSample(level: string, category: LogCategory, config: any): boolean {
    // ERROR级别始终记录
    if (level.toLowerCase() === 'error') {
      return true
    }

    // 如果配置中禁用了采样，则根据分类采样率决定
    if (!config.logging.sampling.enabled) {
      // 即使全局采样关闭，也应用分类采样率
      const categoryRate = this.categorySamplingRates[category] ?? 1.0
      return Math.random() <= categoryRate
    }

    // 结合级别采样率和分类采样率（取较小值，确保采样更严格）
    const levelSampleRate = {
      debug: config.logging.sampling.debug_sample_rate,
      info: config.logging.sampling.info_sample_rate,
      warn: config.logging.sampling.warn_sample_rate,
      error: 1.0,
    }[level.toLowerCase()] || 1.0

    const categoryRate = this.categorySamplingRates[category] ?? 1.0

    // 取两者中的较小值，确保采样更严格
    const finalRate = Math.min(levelSampleRate, categoryRate)

    return Math.random() <= finalRate
  }

  static checkSample(level: string, category?: LogCategory): boolean {
    try {
      const config = getConfig()
      const logCategory = category || LogCategory.SYSTEM
      return this.shouldSample(level, logCategory, config)
    }
    catch {
      // 如果配置未加载，使用分类默认采样率
      if (category) {
        const categoryRate = this.categorySamplingRates[category] ?? 1.0
        return Math.random() <= categoryRate
      }
      return true // 默认记录
    }
  }
}

// 性能监控类
class PerformanceLogger {
  private static timers: Map<string, number> = new Map()

  static start(timerName: string): void {
    this.timers.set(timerName, performance.now())
  }

  static end(timerName: string): number {
    const startTime = this.timers.get(timerName)
    if (!startTime) {
      console.warn(`Timer '${timerName}' not found`)
      return 0
    }
    const duration = performance.now() - startTime
    this.timers.delete(timerName)
    return Math.round(duration * 100) / 100 // 保留两位小数
  }

  static measure(timerName: string): number {
    const startTime = this.timers.get(timerName)
    if (!startTime) {
      return 0
    }
    return Math.round((performance.now() - startTime) * 100) / 100
  }
}

// HTML保存辅助函数
class HtmlLogger {
  private static saveIndex = 0

  static async saveHtml(content: string, filename?: string): Promise<string> {
    try {
      const tempPath = getTempHtmlPath()
      await mkdir(tempPath, { recursive: true })

      const timestamp = dayjs().format('YYYY-MM-DD_HH-mm-ss')
      const name = filename || `page-${++this.saveIndex}`
      const filepath = join(tempPath, `${timestamp}_${name}.html`)

      await writeFile(filepath, content, 'utf8')
      return filepath
    }
    catch (error) {
      console.error('保存HTML失败:', error)
      return ''
    }
  }

  static async saveDebugData(data: any, filename: string): Promise<string> {
    try {
      const tempPath = getTempHtmlPath()
      await mkdir(tempPath, { recursive: true })

      const timestamp = dayjs().format('YYYY-MM-DD_HH-mm-ss')
      const filepath = join(tempPath, `${timestamp}_${filename}.json`)

      await writeFile(filepath, JSON.stringify(data, null, 2), 'utf8')
      return filepath
    }
    catch (error) {
      console.error('保存调试数据失败:', error)
      return ''
    }
  }
}

// 安全序列化（防循环、深度与大小限制）
function safeStringify(input: any, opts?: { maxDepth?: number, maxLen?: number }): string {
  const maxDepth = Math.max(1, opts?.maxDepth ?? 6)
  const maxLen = Math.max(64, opts?.maxLen ?? 20000)
  const seen = new WeakSet()

  function serialize(value: any, depth: number): any {
    if (value === null || value === undefined)
      return value
    if (typeof value === 'string')
      return value.length > 2000 ? `${value.slice(0, 2000)}…[truncated]` : value
    if (typeof value === 'number' || typeof value === 'boolean')
      return value
    if (typeof value === 'bigint')
      return Number(value)
    if (typeof value === 'function' || typeof value === 'symbol')
      return undefined
    if (value instanceof Date)
      return value.toISOString()
    if (Buffer.isBuffer?.(value))
      return `[Buffer ${value.length} bytes]`
    if (Array.isArray(value)) {
      if (depth >= maxDepth)
        return `[Array(${value.length}) depth limit]`
      return value.map(v => serialize(v, depth + 1)).filter(v => v !== undefined)
    }
    if (typeof value === 'object') {
      if (seen.has(value))
        return '[Circular]'
      seen.add(value)
      if (depth >= maxDepth)
        return '[Object depth limit]'
      const out: Record<string, any> = {}
      for (const key of Object.keys(value)) {
        try {
          const v = serialize((value as any)[key], depth + 1)
          if (v !== undefined)
            out[key] = v
        }
        catch {
          out[key] = '[Unserializable]'
        }
      }
      return out
    }
    try {
      return JSON.parse(JSON.stringify(value))
    }
    catch {
      return String(value)
    }
  }

  try {
    let text = JSON.stringify(serialize(input, 0))
    if (text.length > maxLen)
      text = `${text.slice(0, maxLen)}…[truncated ${text.length - maxLen} chars]`
    return text
  }
  catch {
    try {
      const text = JSON.stringify('[Unserializable Meta]')
      return text
    }
    catch {
      return '{}'
    }
  }
}

export async function setupLogger(): Promise<winston.Logger> {
  if (logger)
    return logger

  const config = getConfig()
  const logsPath = getLogsPath()

  // 确保日志目录存在
  try {
    await mkdir(logsPath, { recursive: true })
  }
  catch (error) {
    console.warn('创建日志目录失败:', error)
  }

  // JSON格式化器（用于文件输出，结构化便于分析）
  const jsonFormat = winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format((info) => {
      // 确保包含标准字段
      if (!info.traceId && info.traceId !== false) {
        info.traceId = generateTraceId()
      }
      if (!info.category) {
        info.category = LogCategory.SYSTEM
      }
      if (!info.component) {
        info.component = 'Unknown'
      }
      return info
    })(),
    winston.format.json(),
  )

  // 文本格式化器（用于文件输出，人类可读）
  const textFormat = winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    winston.format.errors({ stack: true }),
    winston.format.printf(({ timestamp, level, message, stack, ...meta }) => {
      let log = `${timestamp} [${level.toUpperCase()}] ${message}`

      // 添加元数据（使用安全序列化，避免循环/过深结构导致栈溢出）
      if (Object.keys(meta).length > 0) {
        log += ` ${safeStringify(meta)}`
      }

      // 添加错误堆栈
      if (stack) {
        log += `\n${stack}`
      }

      return log
    }),
  )

  // 文件日志格式选择：优先使用JSON格式（结构化），但可通过配置切换
  const fileLogFormat = jsonFormat // 默认使用JSON格式，便于分析和检索

  // Console 过滤器（支持在配置中设置 logging.console_focus 仅显示匹配会话/组件的日志）
  const consoleFilter = winston.format((info) => {
    try {
      const cfg: any = getConfig()
      const focus = cfg?.logging?.console_focus
      if (!focus)
        return info
      const focusStr = String(focus)
      if (!focusStr || focusStr.trim().length === 0)
        return info
      const hay = `${info.sessionId || ''} ${info.userName || ''} ${info.passport || ''} ${info.component || ''} ${info.traceId || ''}`
      const tokens = focusStr.split(',').map((s: string) => s.trim()).filter(Boolean)
      for (const tk of tokens) {
        if (hay.includes(tk))
          return info
      }
      return false
    }
    catch {
      return info
    }
  })

  // Console 简洁格式：关键信息放前缀，减少混乱
  const consoleLineFormat = winston.format.printf(({ timestamp, level, message, ...meta }) => {
    const comp = meta.component ? String(meta.component) : ''
    const sid = meta.sessionId ? String(meta.sessionId).slice(-8) : ''
    const trace = meta.traceId ? String(meta.traceId).slice(-6) : ''
    // 仅保留少量常用字段，其他字段不在控制台展开（详见文件日志）
    const prefix = [comp && `[${comp}]`, sid && `[sid:${sid}]`, trace && `[t:${trace}]`].filter(Boolean).join(' ')
    return `${timestamp} [${level.toUpperCase()}] ${prefix} ${message}`.trim()
  })

  const transports: winston.transport[] = []

  // 控制台输出
  if (config.logging.console_output) {
    transports.push(
      new winston.transports.Console({
        level: config.logging.log_level.toLowerCase(),
        format: winston.format.combine(
          consoleFilter(),
          winston.format.colorize(),
          winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
          consoleLineFormat,
        ),
      }),
    )
  }

  // 文件输出
  if (config.logging.file_output) {
    // 创建分类日志文件的辅助函数
    const createCategoryTransport = (category: LogCategory, level?: string) => {
      return new DailyRotateFile({
        filename: join(logsPath, `${category}-%DATE%.log`),
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '20m',
        maxFiles: config.logging.log_retention,
        level: level || config.logging.log_level.toLowerCase(),
        format: winston.format.combine(
          // 只记录指定分类的日志
          winston.format((info) => {
            return info.category === category ? info : false
          })(),
          fileLogFormat,
        ),
      })
    }

    // 按日期轮转的文件日志（通用，使用JSON格式）
    // 注意：这个文件会记录所有分类的日志，作为备份
    transports.push(
      new DailyRotateFile({
        filename: join(logsPath, 'app-%DATE%.log'),
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '20m',
        maxFiles: config.logging.log_retention,
        level: config.logging.log_level.toLowerCase(),
        format: fileLogFormat,
      }),
    )

    // 为关键分类创建独立日志文件
    // 预约业务日志
    transports.push(createCategoryTransport(LogCategory.BOOKING))

    // HTTP请求日志
    transports.push(createCategoryTransport(LogCategory.HTTP))

    // 浏览器操作日志
    transports.push(createCategoryTransport(LogCategory.BROWSER))

    // 监控任务日志
    transports.push(createCategoryTransport(LogCategory.MONITOR))

    // Worker进程日志
    transports.push(createCategoryTransport(LogCategory.WORKER))

    // 代理相关日志
    transports.push(createCategoryTransport(LogCategory.PROXY))

    // 系统日志
    transports.push(createCategoryTransport(LogCategory.SYSTEM))

    // 错误日志单独文件（所有分类的错误日志）
    transports.push(
      new DailyRotateFile({
        filename: join(logsPath, 'error-%DATE%.log'),
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '20m',
        maxFiles: config.logging.log_retention,
        level: 'error',
        format: fileLogFormat,
      }),
    )
  }

  logger = winston.createLogger({
    level: config.logging.log_level.toLowerCase(),
    transports,
    exitOnError: false,
  })

  // 设置 EventEmitter 监听器上限，避免 MaxListenersExceededWarning
  // 因为日志系统可能被多个地方订阅（UI订阅、文件输出等），默认10个限制不够
  if (logger && typeof (logger as any).setMaxListeners === 'function') {
    (logger as any).setMaxListeners(0) // 0 表示无限制
  }
  // 同时为所有 transports 设置监听器上限（winston 的 Transport 也可能触发此警告）
  for (const transport of logger.transports) {
    if (transport && typeof (transport as any).setMaxListeners === 'function') {
      (transport as any).setMaxListeners(0)
    }
  }

  // 记录首次应用的日志配置，用于后续热更新对比
  appliedLogLevel = String(config.logging.log_level || 'INFO').toLowerCase()
  appliedConsoleOutput = !!config.logging.console_output
  appliedFileOutput = !!config.logging.file_output

  // 处理未捕获的异常和拒绝
  logger.exceptions.handle(
    new DailyRotateFile({
      filename: join(logsPath, 'exceptions-%DATE%.log'),
      datePattern: 'YYYY-MM-DD',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d',
      format: fileLogFormat,
    }),
  )

  logger.rejections.handle(
    new DailyRotateFile({
      filename: join(logsPath, 'rejections-%DATE%.log'),
      datePattern: 'YYYY-MM-DD',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d',
      format: fileLogFormat,
    }),
  )

  logger.info('📝 日志系统初始化完成', {
    level: config.logging.log_level,
    console: config.logging.console_output,
    file: config.logging.file_output,
    path: logsPath,
    nodeVersion: process.version,
    platform: process.platform,
    arch: process.arch,
    memoryUsage: process.memoryUsage(),
  })

  return logger
}

export function getLogger(): winston.Logger {
  if (!logger) {
    throw new Error('日志系统尚未初始化，请先调用 setupLogger()')
  }
  return logger
}

// 创建带上下文的日志记录器
export function createContextLogger(context: LogContext) {
  const baseLogger = getLogger()

  return {
    debug: (message: string, meta?: LogContext) =>
      baseLogger.debug(message, { ...addSystemContext({ ...context, ...(meta || {}) }) }),
    info: (message: string, meta?: LogContext) =>
      baseLogger.info(message, { ...addSystemContext({ ...context, ...(meta || {}) }) }),
    warn: (message: string, meta?: LogContext) =>
      baseLogger.warn(message, { ...addSystemContext({ ...context, ...(meta || {}) }) }),
    error: (message: string, meta?: LogContext) =>
      baseLogger.error(message, { ...addSystemContext({ ...context, ...(meta || {}) }) }),
  }
}

// 日志清理函数
export async function cleanupLogs(olderThanDays: number = 7): Promise<number> {
  try {
    const logsPath = getLogsPath()
    const { readdir, unlink, stat } = await import('node:fs/promises')

    const files = await readdir(logsPath)
    let deletedCount = 0

    const cutoffDate = dayjs().subtract(olderThanDays, 'day').toDate()

    for (const file of files) {
      if (file.endsWith('.log')) {
        const filePath = join(logsPath, file)
        const stats = await stat(filePath)

        if (stats.mtime < cutoffDate) {
          await unlink(filePath)
          deletedCount++
        }
      }
    }

    getLogger().info(`🧹 日志清理完成`, { deletedCount, olderThanDays })
    return deletedCount
  }
  catch (error) {
    getLogger().error('日志清理失败', { error: String(error) })
    return 0
  }
}

// 获取日志文件统计信息
export async function getLogFileStats(): Promise<{
  totalFiles: number
  totalSize: number
  oldestFile: string
  newestFile: string
}> {
  try {
    const logsPath = getLogsPath()
    const { readdir, stat } = await import('node:fs/promises')

    const files = await readdir(logsPath)
    const logFiles = files.filter(file => file.endsWith('.log'))

    let totalSize = 0
    let oldestTime = dayjs().valueOf()
    let newestTime = 0
    let oldestFile = ''
    let newestFile = ''

    for (const file of logFiles) {
      const filePath = join(logsPath, file)
      const stats = await stat(filePath)

      totalSize += stats.size

      if (stats.mtime.getTime() < oldestTime) {
        oldestTime = stats.mtime.getTime()
        oldestFile = file
      }

      if (stats.mtime.getTime() > newestTime) {
        newestTime = stats.mtime.getTime()
        newestFile = file
      }
    }

    return {
      totalFiles: logFiles.length,
      totalSize: Math.round(totalSize / 1024), // KB
      oldestFile,
      newestFile,
    }
  }
  catch (error) {
    getLogger().error('获取日志统计信息失败', { error: String(error) })
    return {
      totalFiles: 0,
      totalSize: 0,
      oldestFile: '',
      newestFile: '',
    }
  }
}

// 增强的日志方法（带采样和指标）
function logWithSampling(level: string, logger: winston.Logger, message: string, meta?: LogContext) {
  // 添加指标收集
  LogMetrics.increment(`log.${level}`)

  // 获取日志分类（从meta中获取，或使用默认值）
  const category = meta?.category || LogCategory.SYSTEM

  // 检查采样（传入分类）
  if (!LogSampler.checkSample(level, category)) {
    LogMetrics.increment(`log.${level}.sampled`)
    LogMetrics.increment(`log.${level}.${category}.sampled`)
    return
  }

  // 自动生成traceId和增强上下文
  // 对敏感数据进行脱敏处理
  const sanitizedMeta = sanitize(meta)

  const contextWithTrace = addSystemContext({
    ...sanitizedMeta,
    category, // 确保包含分类
    traceId: sanitizedMeta?.traceId || generateTraceId(),
  })

  logger[level as keyof winston.Logger](message, contextWithTrace)
}

export const log = {
  debug: (message: string, meta?: LogContext) => { applyRuntimeLoggingConfigIfNeeded(); return logWithSampling('debug', getLogger(), message, meta) },
  info: (message: string, meta?: LogContext) => { applyRuntimeLoggingConfigIfNeeded(); return logWithSampling('info', getLogger(), message, meta) },
  warn: (message: string, meta?: LogContext) => { applyRuntimeLoggingConfigIfNeeded(); return logWithSampling('warn', getLogger(), message, meta) },
  error: (message: string, meta?: LogContext) => { applyRuntimeLoggingConfigIfNeeded(); return logWithSampling('error', getLogger(), message, meta) },

  // 性能日志
  performance: (operation: string, duration: number, meta?: LogContext) => {
    LogMetrics.increment('log.performance')
    const contextWithTrace = {
      ...addSystemContext(meta),
      traceId: meta?.traceId || generateTraceId(),
      operation,
      duration: `${duration}ms`,
      category: LogCategory.PERFORMANCE,
      component: meta?.component || 'PerformanceMonitor',
    }
    applyRuntimeLoggingConfigIfNeeded()
    getLogger().info(`⚡ 性能监控: ${operation}`, contextWithTrace)
  },

  // HTTP请求日志
  http: (method: string, url: string, status: number, duration: number, meta?: LogContext) => {
    const level = status >= 400 ? 'error' : status >= 300 ? 'warn' : 'info'
    LogMetrics.increment(`log.http.${level}`)
    LogMetrics.increment(`log.http.status.${status}`)

    const contextWithTrace = {
      ...addSystemContext(meta),
      traceId: meta?.traceId || generateTraceId(),
      method,
      url,
      status,
      duration: `${duration}ms`,
      category: LogCategory.HTTP,
      component: meta?.component || 'HttpClient',
    }
    applyRuntimeLoggingConfigIfNeeded()
    getLogger()[level](`🌐 HTTP ${method} ${url}`, contextWithTrace)
  },

  // 预约流程专用日志
  booking: {
    start: (sessionId: string, userInfo: any, meta?: LogContext) => {
      getLogger().info('🚀 预约流程开始', {
        ...addSystemContext(meta),
        sessionId,
        userName: userInfo.license_owner_name,
        passport: userInfo.passport_number,
        category: LogCategory.BOOKING,
        step: 'start',
        component: meta?.component || 'BookingEngine',
      })
    },

    step: (sessionId: string, stepName: string, status: 'start' | 'success' | 'warn' | 'error', duration?: number, meta?: LogContext) => {
      const emoji = status === 'success' ? '✅' : status === 'error' ? '❌' : status === 'warn' ? '⚠️' : '⏳'
      const level = status === 'error' ? 'error' : status === 'warn' ? 'warn' : 'info'

      getLogger()[level](`${emoji} 预约步骤: ${stepName}`, {
        // 确保级别热更新
        ...(applyRuntimeLoggingConfigIfNeeded(), {}),
        ...addSystemContext(meta),
        sessionId,
        step: stepName,
        status,
        duration: duration ? `${duration}ms` : undefined,
        category: LogCategory.BOOKING,
        component: meta?.component || 'BookingEngine',
      })
    },

    end: (sessionId: string, success: boolean, result: any, totalDuration: number, meta?: LogContext) => {
      const emoji = success ? '🎉' : '💥'
      const level = success ? 'info' : 'error'

      applyRuntimeLoggingConfigIfNeeded()
      getLogger()[level](`${emoji} 预约流程${success ? '成功' : '失败'}`, {
        ...addSystemContext(meta),
        sessionId,
        success,
        referenceNumber: result.reference_number,
        // 记录预约日期和时间（便于修复脚本从日志中提取）
        日期: result.selected_date,
        时间: result.selected_timeslot,
        errorMessage: result.message,
        totalDuration: `${totalDuration}ms`,
        category: LogCategory.BOOKING,
        component: meta?.component || 'BookingEngine',
      })
    },
  },

  // 系统监控日志
  system: {
    memory: () => {
      const usage = process.memoryUsage()
      applyRuntimeLoggingConfigIfNeeded()
      getLogger().info('💾 内存使用情况', {
        ...addSystemContext(),
        rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
        heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
        heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
        external: `${Math.round(usage.external / 1024 / 1024)}MB`,
        category: 'system',
      })
    },

    error: (error: Error, context: string, meta?: LogContext & {
      user_action?: string
      recovery_suggestion?: string
    }) => {
      LogMetrics.increment('log.system.error')
      const contextWithTrace = {
        ...addSystemContext(meta),
        traceId: meta?.traceId || generateTraceId(),
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
          code: (error as any).code,
        },
        context,
        user_action: meta?.user_action,
        recovery_suggestion: meta?.recovery_suggestion,
        category: LogCategory.SYSTEM,
        component: meta?.component || context,
      }
      applyRuntimeLoggingConfigIfNeeded()
      getLogger().error(`💥 系统错误 [${context}]`, contextWithTrace)
    },
  },
}

// 添加系统上下文信息
function addSystemContext(meta?: LogContext): LogContext {
  const now = dayjs()
  return {
    ...meta,
    timestamp: now.toISOString(),
    pid: process.pid,
    uptime: Math.round(process.uptime()),
    memoryUsed: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
    // 确保包含 traceId（如果未提供）
    traceId: meta?.traceId || generateTraceId(),
    // 确保包含 category（如果未提供，默认 SYSTEM）
    category: meta?.category || LogCategory.SYSTEM,
    // 确保包含 component（如果未提供，使用 meta.component 或 'Unknown'）
    component: meta?.component || 'Unknown',
  }
}

// 日志搜索选项接口
export interface LogSearchOptions {
  level?: string[]
  date_range?: { start: string, end: string }
  trace_id?: string
  correlation_id?: string
  component?: string
  category?: string
  keyword?: string
  limit?: number
  offset?: number
}

// 导出新的日志功能
export { HtmlLogger, LogMetrics, PerformanceLogger }

// 导出日志统计指标
export function getLogMetrics(): Record<string, number> {
  return LogMetrics.getMetrics()
}

export function getLogStats(): { totalLogs: number, uptime: number, metricsAge: number } {
  return LogMetrics.getStats()
}

export function resetLogMetrics(): void {
  LogMetrics.resetMetrics()
}

// 日志搜索功能（基础实现）
export async function searchLogs(options: LogSearchOptions): Promise<{
  results: any[]
  total: number
  hasMore: boolean
}> {
  try {
    // 这里实现基本的日志搜索功能
    // 可以后续扩展为更复杂的搜索引擎
    const { readFile } = await import('node:fs/promises')
    const { readdir } = await import('node:fs/promises')

    const logsPath = getLogsPath()
    const files = await readdir(logsPath)
    const logFiles = files.filter(file => file.endsWith('.log'))

    let results: any[] = []
    let totalFound = 0

    for (const file of logFiles) {
      if (options.date_range) {
        const match = file.match(/(\d{4}-\d{2}-\d{2})/)
        if (match) {
          const fileDate = match[1]
          if (fileDate < options.date_range.start || fileDate > options.date_range.end) {
            continue
          }
        }
      }

      const filePath = join(logsPath, file)
      const content = await readFile(filePath, 'utf-8')
      const lines = content.split('\n')

      for (const line of lines) {
        if (!line.trim())
          continue

        try {
          // 尝试解析日志行
          const logEntry = JSON.parse(line.split('] ')[1] || '{}')

          // 应用过滤条件
          if (options.level && !options.level.includes(logEntry.level))
            continue
          if (options.trace_id && logEntry.traceId !== options.trace_id)
            continue
          if (options.component && logEntry.component !== options.component)
            continue
          if (options.category && logEntry.category !== options.category)
            continue
          if (options.keyword && !line.toLowerCase().includes(options.keyword.toLowerCase()))
            continue

          results.push({
            timestamp: logEntry.timestamp,
            level: logEntry.level,
            message: `${line.split('] ')[0]}] ${line.split('] ')[1]?.split(' {')[0] || ''}`,
            metadata: logEntry,
            file,
          })
          totalFound++

          if (options.limit && results.length >= options.limit) {
            break
          }
        }
        catch {
          // 如果无法解析为JSON，按纯文本处理
          if (options.keyword && line.toLowerCase().includes(options.keyword.toLowerCase())) {
            results.push({
              timestamp: dayjs().toISOString(),
              level: 'unknown',
              message: line,
              metadata: {},
              file,
            })
            totalFound++
          }
        }
      }

      if (options.limit && results.length >= options.limit) {
        break
      }
    }

    // 应用偏移
    if (options.offset) {
      results = results.slice(options.offset)
    }

    return {
      results: results.slice(0, options.limit || 100),
      total: totalFound,
      hasMore: totalFound > (options.limit || 100),
    }
  }
  catch (error) {
    getLogger().error('搜索日志失败', { error: String(error) })
    return {
      results: [],
      total: 0,
      hasMore: false,
    }
  }
}

// 创建带追踪ID的上下文日志记录器
export function createTrackedContextLogger(context: LogContext, traceId?: string) {
  const baseLogger = getLogger()
  const fullContext = {
    ...context,
    traceId: traceId || generateTraceId(),
  }

  return {
    debug: (message: string, meta?: LogContext) =>
      baseLogger.debug(message, { ...fullContext, ...addSystemContext(meta) }),
    info: (message: string, meta?: LogContext) =>
      baseLogger.info(message, { ...fullContext, ...addSystemContext(meta) }),
    warn: (message: string, meta?: LogContext) =>
      baseLogger.warn(message, { ...fullContext, ...addSystemContext(meta) }),
    error: (message: string, meta?: LogContext) =>
      baseLogger.error(message, { ...fullContext, ...addSystemContext(meta) }),
  }
}
